#include<my_header.h>

typedef struct train{
    int length;
    char data[1000];
}train_t;

int recvn(int sockfd,void* buf,int length){
    int total=0;
    char *p=(char *)buf;
    while(total<length){
        ssize_t sret=recv(sockfd,p,length-total,0);
        total+=sret;
        p+sret;
    }
    return total;
}

//发总文件大小使用while的方式获得完整包的数据
// int recvfile(int netfd){
//     train_t train;
//     char filename[4096]={0};
//     printf("进入recvfile函数\n");
//     // recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
//     recvn(netfd,&train.length,sizeof(int));
//     if(train.length==0){ //服务端关闭
//         printf("异常！:应该收到文件名\n");
//     }
//     recvn(netfd,&train.data,train.length);
//     memcpy(filename,train.data,train.length);

//     int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);


//     // 错误：服务端不发送文件大小，客户端无法通过获取的文件名，来推断大小
//     // struct  stat statbuf;
//     // bzero(&statbuf,sizeof(statbuf)); 
//     // stat(filename,&statbuf);
//     // off_t filesize=statbuf.st_size;

//     off_t filesize;
//     recvn(netfd,&train.length,sizeof(train.length));
//     recvn(netfd,train.data,sizeof(train.length));
//     memcpy(&filesize,train.data,train.length);
//     off_t donesize=0;
//     off_t lastsize=0;
//     off_t slice=filesize/10000;

//     while(1){
//         bzero(&train,sizeof(train));
//         // recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
//         recvn(netfd,train.data,train.length);
//         if(train.length==0){
//             break;
//         }
//         donesize+=train.length;
//         if(donesize-lastsize>=slice){
//             printf("%5.2ld%%/r",100.0*donesize/filesize);
//             fflush(stdout);
//             lastsize=donesize;
//         }
//         recvn(netfd,train.data,train.length);
//         write(fd,train.data,train.length);
//     }
//     printf("100%%\n");
//     close(fd);
//     return 0;
// }

//mmap()版本的显示下载进度大小，
int recvmmap(int sockfd,char* p,off_t length){
    off_t donesize=0;
    off_t lastsize=0;
    off_t slice=length/10000;
    while(donesize<length){
        ssize_t sret=recv(sockfd,p,length-donesize,0);
        donesize+=sret;
        if(donesize-lastsize>=length){
            printf("%5.2ld%%/r",100.0*donesize/length);
            fflush(stdout);
            lastsize=donesize;
        }
        p+sret;
    }
    printf("100%%\n");
    return donesize;
}

int recvfile(int netfd){
    train_t train;
    char filename[4096]={0};
    printf("进入recvfile函数\n");
    recvn(netfd,&train.length,sizeof(int));
    if(train.length==0){ //服务端关闭
        printf("异常！:应该收到文件名\n");
    }
    recvn(netfd,&train.data,train.length);
    memcpy(filename,train.data,train.length);

    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);

    
    off_t filesize;
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,sizeof(train.length));
    memcpy(&filesize,train.data,train.length);
    printf("filename=%s , filesize=%ld\n",filename,filesize);

    ftruncate(fd,filesize);
    char *p=(char*) mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    revcmmap(netfd,p,filesize);
    munmap(p,filesize);
    // off_t donesize=0;
    // off_t lastsize=0;
    // off_t slice=filesize/10000;

    // while(1){
    //     bzero(&train,sizeof(train));
      
    //     recvn(netfd,train.data,train.length);
    //     if(train.length==0){
    //         break;
    //     }
    //     donesize+=train.length;
    //     if(donesize-lastsize>=slice){
    //         printf("%5.2ld%%/r",100.0*donesize/filesize);
    //         fflush(stdout);
    //         lastsize=donesize;
    //     }
    //     recvn(netfd,train.data,train.length);
    //     write(fd,train.data,train.length);
    // }
    // printf("100%%\n");
    close(fd);
    return 0;
}

int recvfile(int netfd){
    train_t train;
    char filename[4096]={0};
    printf("进入recvfile函数\n");
    // recv(netfd,&train.length,sizeof(int),MSG_WAITALL);
    recvn(netfd,&train.length,sizeof(int));
    if(train.length==0){ //服务端关闭
        printf("异常！:应该收到文件名\n");
    }
    recvn(netfd,&train.data,train.length);
    memcpy(filename,train.data,train.length);

    int fd=open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);


    // 错误：服务端不发送文件大小，客户端无法通过获取的文件名，来推断大小
    // struct  stat statbuf;
    // bzero(&statbuf,sizeof(statbuf)); 
    // stat(filename,&statbuf);
    // off_t filesize=statbuf.st_size;

    off_t filesize;
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,sizeof(train.length));
    memcpy(&filesize,train.data,train.length);
    off_t donesize=0;
    off_t lastsize=0;
    off_t slice=filesize/10000;

    while(1){
        bzero(&train,sizeof(train));
        // recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
        recvn(netfd,train.data,train.length);
        if(train.length==0){
            break;
        }
        donesize+=train.length;
        if(donesize-lastsize>=slice){
            printf("%5.2ld%%/r",100.0*donesize/filesize);
            fflush(stdout);
            lastsize=donesize;
        }
        recvn(netfd,train.data,train.length);
        write(fd,train.data,train.length);
    }
    printf("100%%\n");
    close(fd);
    return 0;
}

int main(int argc, char *argv[])
{
    // ./client 192.168.72.128 12345
    ARGS_CHECK(argc,3);
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    int ret = connect(sockfd,(struct sockaddr *)&addr,sizeof(addr));
    ERROR_CHECK(ret,-1,"connect");

    fd_set set;
    
    FD_ZERO(&set);
    FD_SET(sockfd,&set);
    select(sockfd+1,&set,NULL,NULL,NULL);
    if(FD_ISSET(sockfd,&set)){
        recvfile(sockfd);
        printf("下载文件完成\n");
    }

    
    // recvfile(sockfd);
    // printf("下载文件完成\n");
    // close(sockfd);
    return 0;
}